﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace Bildverarbeitung.CGFilter
{
    class PaulheimAnnikaFilter : IFilter
    {
        public Bitmap GetSummerizedDifferencefromAverage(Bitmap[] images)
        {
            int imageAmount = images.Length;

            int width = images[0].Width;
            int height = images[0].Height;
            Rectangle rectangle = new Rectangle(0, 0, width, height);
            System.Drawing.Bitmap destination = new System.Drawing.Bitmap(width, height);

            // Array mit allen Pointern auf die Bitmaps
            unsafe
            {
                BitmapData destData = destination.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte* destPointer = (byte*)destData.Scan0.ToPointer();

                BitmapData[] sourceData = new BitmapData[imageAmount];
                byte*[] sourcePointer = new byte*[imageAmount];
                for (int i = 0; i < imageAmount; i++)
                {
                    sourceData[i] = images[i].LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    sourcePointer[i] = (byte*)sourceData[i].Scan0.ToPointer();
                }

                int red = 0;
                int green = 0;
                int blue = 0;
                float redAv, greenAv, blueAv;
                float greenAvL = 0;
                float blueAvL = 0;
                float redAvL = 0;
                int greenAvLAmount = 0;
                int blueAvLAmount = 0;
                int redAvLAmount = 0;
                float greenAvH = 0;
                float blueAvH = 0;
                float redAvH = 0;
                int greenAvHAmount = 0;
                int blueAvHAmount = 0;
                int redAvHAmount = 0;
                byte[] redA = new byte[imageAmount];
                byte[] greenA = new byte[imageAmount];
                byte[] blueA = new byte[imageAmount];
                byte* dest;

                // iteriere über alle Pixel
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        // aller Bilder
                        for (int i = 0; i < imageAmount; i++)
                        {
                            blue += *(sourcePointer[i] + (y * width + x) * 3);
                            green += *(sourcePointer[i] + (y * width + x) * 3 + 1);
                            red += *(sourcePointer[i] + (y * width + x) * 3 + 2);
                            blueA[i] = *(sourcePointer[i] + (y * width + x) * 3);
                            greenA[i] = *(sourcePointer[i] + (y * width + x) * 3 + 1);
                            redA[i] = *(sourcePointer[i] + (y * width + x) * 3 + 2);

                        }
                        redAv = ((float)red / (float)imageAmount);
                        greenAv = ((float)green / (float)imageAmount);
                        blueAv = ((float)blue / (float)imageAmount);


                        // berechne oberen und unteren Durchschnitt
                        for (int i = 0; i < imageAmount; i++)
                        {
                            if (redA[i] < redAv)
                            {
                                redAvL += redA[i];
                                redAvLAmount++;
                            }
                            else
                            {
                                redAvH += redA[i];
                                redAvHAmount++;
                            }

                            if (greenA[i] < greenAv)
                            {
                                greenAvL += greenA[i];
                                greenAvLAmount++;
                            }
                            else
                            {
                                greenAvH += greenA[i];
                                greenAvHAmount++;
                            }

                            if (blueA[i] < blueAv)
                            {
                                blueAvL += blueA[i];
                                blueAvLAmount++;
                            }
                            else
                            {
                                blueAvH += blueA[i];
                                blueAvHAmount++;
                            }
                        }

                        // welcher Durchschnitt ist näher am allgemeinen Durchschnitt?

                        redAv = (redAvLAmount > redAvHAmount) ? redAvL / redAvLAmount : redAvH / redAvHAmount;
                        greenAv = (greenAvLAmount > greenAvHAmount) ? greenAvL / greenAvLAmount : greenAvH / greenAvHAmount;
                        blueAv = (blueAvLAmount > blueAvHAmount) ? blueAvL / blueAvLAmount : blueAvH / blueAvHAmount;



                        dest = destPointer + (y * width + x) * 3;
                        *dest = (byte)(int)blueAv;
                        dest++;
                        *dest = (byte)(int)greenAv;
                        dest++;
                        *dest = (byte)(int)redAv;

                        blue = 0;
                        green = 0;
                        red = 0;
                        blueAvH = 0;
                        greenAvH = 0;
                        redAvH = 0;
                        blueAvL = 0;
                        greenAvL = 0;
                        redAvL = 0;
                        blueAvHAmount = 0;
                        greenAvHAmount = 0;
                        redAvHAmount = 0;
                        blueAvLAmount = 0;
                        greenAvLAmount = 0;
                        redAvLAmount = 0;
                    }
                }

                // unlock bits
                for (int i = 0; i < imageAmount; i++)
                {
                    images[i].UnlockBits(sourceData[i]);
                }
                destination.UnlockBits(destData);
            }

            return destination;
        }

        public String GetName()
        {
            return "PaulheimAnnika";
        }
    }
}
